package edu.yctc.origin.controller.impl;

import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import edu.yctc.origin.constant.ErrorText;
import edu.yctc.origin.constant.StaticPath;
import edu.yctc.origin.constant.TemplatePath;
import edu.yctc.origin.controller.UserController;
import edu.yctc.origin.controller.session.SessionContentHolder;
import edu.yctc.origin.controller.verification.VerificationCodeHolder;
import edu.yctc.origin.entity.ResultDO;
import edu.yctc.origin.entity.UserDO;
import edu.yctc.origin.service.UserIService;
import edu.yctc.origin.vo.MailCaptchaVO;
import edu.yctc.origin.vo.RetrievePasswordByMailVO;
import edu.yctc.origin.vo.UpdateMailVO;
import edu.yctc.origin.vo.UpdatePasswordVO;

/**
 * userController实现类
 * 
 * @author 赵宜珺
 */
@Controller
@RequestMapping("/user")
public class UserControllerImpl implements UserController {

    private final static Logger LOG = LoggerFactory.getLogger("controllerLogger");

    @Autowired
    private UserIService userService;

    @Override
    @GetMapping("signin")
    public String showSignin(HttpSession httpSession, Model model) {
        // 判断是否已经登陆，如果登陆直接跳转登陆成功页
        ResultDO<Long> resultDO = SessionContentHolder.judgeSignin(httpSession.getId());
        if (resultDO.isSuccess() == true) {
            long id = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
            LOG.info("user already signin, userId={}", id);
            String number = userService.getUserDOById(id).getModule().getNumber();
            model.addAttribute("number", number);
            return TemplatePath.USER_SIGNIN_SUCCESS;
        }
        // 未登陆，跳转登陆页
        return TemplatePath.USER_SIGNIN;
    }

    @Override
    @PostMapping("signin")
    public String signin(@ModelAttribute UserDO userDO, HttpSession httpSession, Model model) {
        // 参数检验
        if (StringUtils.isBlank(userDO.getNumber()) || StringUtils.isBlank(userDO.getPassword())) {
            LOG.error("signin fail, parameter invalid, userDO={}", userDO);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        try {
            ResultDO<Long> resultDO = userService.signin(userDO);
            if (resultDO.isSuccess() == false) {
                LOG.error("sigin fail, userDO={}, resultDO={}", userDO, resultDO);
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
            }
            long userId = resultDO.getModule();
            if (userId <= 0) {
                LOG.error("sign in fail, userDO={}, sessionId={}, resultDO={}", userDO, httpSession.getId(), resultDO);
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
            }
            // 登陆成功
            SessionContentHolder.addSignInUserId(httpSession.getId(), resultDO.getModule());
            LOG.info("sign in success, userDO={}, sessionId={}", userDO, httpSession.getId());
            String number = userDO.getNumber();
            model.addAttribute("number", number);
            return TemplatePath.USER_SIGNIN_SUCCESS;
        } catch (Exception e) {
            LOG.error("signin error, userDO={}", userDO, e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
    }

    @Override
    @GetMapping("home")
    public String showUserHome(HttpSession httpSession, Model model) {
        long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
        ResultDO<UserDO> resultDO = userService.getUserDOById(userId);
        if (resultDO.isSuccess() == false) {
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
        }
        model.addAttribute("number", resultDO.getModule().getNumber());
        return TemplatePath.USER_HOME;
    }

    @Override
    @GetMapping("signout")
    public String showSignout() {
        return TemplatePath.USER_SIGNOUT;
    }

    @Override
    @PostMapping("signout")
    public String signout(HttpSession httpSession) {
        if (StringUtils.isBlank(httpSession.getId())) {
            LOG.error("session error, session={}", httpSession);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        try {
            long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
            if (userId <= 0) {
                LOG.error("sign out error, userId <= 0, sessionId={}", httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.NO_SUCH_USER;
            }

            ResultDO<UserDO> getUserDOByIdResultDO = userService.getUserDOById(userId);
            if (getUserDOByIdResultDO.isSuccess() == false) {
                LOG.error("sign out fail, userId={}, session={}, resultDO={}", userId, httpSession,
                    getUserDOByIdResultDO);
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + getUserDOByIdResultDO.getMsg();
            }
        } catch (Exception e) {
            LOG.error("sign out error, sessionId={}", httpSession.getId(), e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
        LOG.info("sign out success, sessionId={}, userId={}", httpSession.getId(),
            SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId()));
        SessionContentHolder.deleteSignInSessionBySessionId(httpSession.getId());
        return TemplatePath.USER_SIGNOUT_SUCCESS;
    }

    @Override
    @GetMapping("update-password")
    public String showUpdatePassword() {
        return TemplatePath.USER_UPDATE_PASSWORD;
    }

    @Override
    @PostMapping("update-password")
    public String updatePassword(UpdatePasswordVO updatePasswordVO, HttpSession httpSession) {
        // 0. 参数校验
        if (StringUtils.isBlank(updatePasswordVO.getOldPassword())
            || StringUtils.isBlank(updatePasswordVO.getNewPassword())
            || StringUtils.isBlank(updatePasswordVO.getConfirmNewPassword())) {
            LOG.error("parameter illegal, updatePasswordVO={}, sessionId={}", updatePasswordVO, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        if (StringUtils.isBlank(httpSession.getId())) {
            LOG.error("session error, updatePasswordVO={}, sessionId={}", updatePasswordVO, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }

        // 新密码二次输入校验
        if (StringUtils.equals(updatePasswordVO.getNewPassword(), updatePasswordVO.getConfirmNewPassword()) == false) {
            LOG.error("parameter illegal, updatePasswordVO={}, sessionId={}", updatePasswordVO, httpSession.getId());
            // 重定向到错误页
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.CONFIRM_INVALID;
        }

        try {
            // 1. service入参准备
            long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
            ResultDO<UserDO> getUserDOByIdresultDO = userService.getUserDOById(userId);
            // 返回值成功判断
            if (getUserDOByIdresultDO.isSuccess() == false) {
                LOG.error("get user by id fail, resultDO={}, updatePasswordVO={}, sessionId={}", getUserDOByIdresultDO,
                    updatePasswordVO, httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + getUserDOByIdresultDO.getMsg();
            }
            UserDO userDO = getUserDOByIdresultDO.getModule();

            // 3. 调用service
            ResultDO<Void> resultDO = userService.updatePassword(userDO, updatePasswordVO.getOldPassword(),
                updatePasswordVO.getNewPassword());
            if (resultDO.isSuccess() == false) {
                LOG.error("updatedate password fail, updatePasswordVO={}, resultDO={}, sessionId={}", updatePasswordVO,
                    resultDO, httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
            }
            SessionContentHolder.deleteSignInSessionBySessionId(httpSession.getId());
            // 重新种session
            SessionContentHolder.addSignInUserId(httpSession.getId(), userId);
            LOG.info("update password success, updatePasswordVO={}, sessionId={}", updatePasswordVO,
                httpSession.getId());
            return TemplatePath.USER_UPDATE_PASSWORD_SUCCESS;
        } catch (Exception e) {
            LOG.error("update password error, updatePasswordVO={}, sessionId={}", updatePasswordVO, httpSession.getId(),
                e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
    }

    @Override
    @GetMapping("verify-identity-step-a")
    public String showRetrievePassword() {
        return TemplatePath.USER_RETRIEVE_PASSWORDB_START;
    }

    @Override
    @GetMapping("verify-identity-step-b-email")
    public String showRetrievePasswordByMail() {
        return TemplatePath.USER_RETRIEVE_PASSWORD_BY_MAIL;
    }

    @Override
    @PostMapping("verify-identity-step-b-email")
    public String retrievePasswordByMail(@ModelAttribute RetrievePasswordByMailVO retrievePasswordByMailVO,
        HttpSession httpSession) {
        // 0.参数验证
        if (StringUtils.isBlank(retrievePasswordByMailVO.getMail())
            || StringUtils.isBlank(retrievePasswordByMailVO.getVerificationCode())) {
            LOG.error("parameter illegal, retrievePasswordByMailVO={}, sessionId={}", retrievePasswordByMailVO,
                httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        String mail = retrievePasswordByMailVO.getMail();
        String verificationCode = retrievePasswordByMailVO.getVerificationCode();
        boolean checkResult = VerificationCodeHolder.checkMailVerificationCode(mail, verificationCode);

        if (checkResult == false) {
            LOG.error("verificationCode not match, verificationCode={}, sessionId={}", verificationCode,
                httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.VERIFICATION_CODE_NOT_MATCH;
        }
        LOG.info("verificationCode match success, retrievePasswordByMailVO={}, sessionId={}", retrievePasswordByMailVO,
            httpSession.getId());
        SessionContentHolder.addMail(httpSession.getId(), retrievePasswordByMailVO.getMail());
        return TemplatePath.USER_RETRIEVE_PASSWORDB;
    }

    @Override
    @GetMapping("mail-authentication")
    public String showMailAuthentication(ModelMap map, HttpSession httpSession) {
        long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
        ResultDO<UserDO> getUserDOByIdResultDO = userService.getUserDOById(userId);
        if (getUserDOByIdResultDO.isSuccess() == false) {
            LOG.error("mail authentication get UserDO by id fail, getUserDOByIdResultDO={}, map={}, sessionId={}",
                getUserDOByIdResultDO, map, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + getUserDOByIdResultDO.getMsg();
        }
        UserDO userDO = getUserDOByIdResultDO.getModule();
        if (userDO == null) {
            LOG.error("mail authentication userDO is null, userDO={}, userId={}", userDO, userId);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.NO_SUCH_USER;
        }
        map.addAttribute("userDO", userDO);
        map.addAttribute("mailCaptchaVO", new MailCaptchaVO());
        return TemplatePath.USER_MAIL_AUTHENTICATION;
    }

    @Override
    @PostMapping("mail-authentication")
    public String mailAuthentication(@ModelAttribute MailCaptchaVO mailCaptchaVO, HttpSession httpSession) {
        // 验证邮箱验证码
        // 0.参数验证
        if (StringUtils.isBlank(mailCaptchaVO.getCaptchaFromFront())) {
            LOG.error("mail authentication parameter illegal, mailCaptchaVO={}, sessionId={}", mailCaptchaVO,
                httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        if (StringUtils.isBlank(httpSession.getId())) {
            LOG.error("mail authentication session is null, mailCaptchaVO={}, sessionId={}", mailCaptchaVO,
                httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        // 1. service入参准备
        UserDO userDO;
        try {
            long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
            ResultDO<UserDO> getUserDOByIdResultDO = userService.getUserDOById(userId);
            if (getUserDOByIdResultDO.isSuccess() == false) {
                LOG.error(
                    "mail authentication get UserDO by id fail, getUserDOByIdResultDO={}, mailCaptchaVO={}, sessionId={}",
                    getUserDOByIdResultDO, mailCaptchaVO, httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + getUserDOByIdResultDO.getMsg();
            }
            userDO = getUserDOByIdResultDO.getModule();
            if (userDO == null) {
                LOG.error("mail authentication userDO is null, userDO={}, userId={}", userDO, userId);
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.NO_SUCH_USER;
            }
        } catch (Exception e) {
            LOG.error("mail authentication session error, mailCaptchaVO={}, sessionId={}", mailCaptchaVO,
                httpSession.getId(), e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
        String mail = null;
        String getCaptchaFromFront = null;
        try {
            mail = userDO.getMail();
            getCaptchaFromFront = mailCaptchaVO.getCaptchaFromFront();
        } catch (Exception e) {
            LOG.error("mail authentication mail or getCaptchaFromFront error, mail={}, getCaptchaFromFront={}", mail,
                getCaptchaFromFront, e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
        // 2. 验证码托管
        boolean checkResult = VerificationCodeHolder.checkMailVerificationCode(mail, getCaptchaFromFront);
        if (checkResult == false) {
            LOG.error("mail authentication verificationCode not match, mail={}, getCaptchaFromFront={}", mail,
                getCaptchaFromFront);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.VERIFICATION_CODE_NOT_MATCH;
        }
        LOG.info("mail authentication captcha match success, mail={}, getCaptchaFromFront={}", mail,
            getCaptchaFromFront);
        SessionContentHolder.addMail(httpSession.getId(), userDO.getMail());
        return TemplatePath.USER_UPDATE_MAIL;
    }

    @Override
    @PostMapping("update-mail")
    public String updateMail(@ModelAttribute UpdateMailVO updateMailVO, HttpSession httpSession) {
        // 验证邮箱验证码
        // 0.参数验证
        if (StringUtils.isBlank(updateMailVO.getMail()) || StringUtils.isBlank(updateMailVO.getCaptchaFromFront())) {
            LOG.error("update mail parameter illegal, updateMailVO={}, sessionId={}", updateMailVO,
                httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        if (StringUtils.isBlank(httpSession.getId())) {
            LOG.error("update mail session error, mailCaptchaVO={}, sessionId={}", updateMailVO, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }
        String mail = null;
        String getCaptchaFromFront = null;
        try {
            mail = updateMailVO.getMail();
            getCaptchaFromFront = updateMailVO.getCaptchaFromFront();
        } catch (Exception e) {
            LOG.error("update mail mail or getCaptchaFromFront error, mail={}, getCaptchaFromFront={}", mail,
                getCaptchaFromFront, e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
        boolean checkResult = VerificationCodeHolder.checkMailVerificationCode(mail, getCaptchaFromFront);
        if (checkResult == false) {
            LOG.error("update mail verificationCode not match, mail={}, getCaptchaFromFront={}", mail,
                getCaptchaFromFront);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.VERIFICATION_CODE_NOT_MATCH;
        }

        LOG.info("update mail verificationCode match success, updateMailVO={}, sessionId={}", updateMailVO,
            httpSession.getId());
        SessionContentHolder.addMail(httpSession.getId(), updateMailVO.getMail());

        // 修改原邮箱值
        // 1. service入参准备
        UserDO userDO;
        try {
            long userId = SessionContentHolder.getSignInUserIdBySessionId(httpSession.getId());
            ResultDO<UserDO> getUserDOByIdResultDO = userService.getUserDOById(userId);
            if (getUserDOByIdResultDO.isSuccess() == false) {
                LOG.error("update mail get UserDO by id fail, getUserDOByIdResultDO={}, updateMailVO={}, sessionId={}",
                    getUserDOByIdResultDO, updateMailVO, httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + getUserDOByIdResultDO.getMsg();
            }
            userDO = getUserDOByIdResultDO.getModule();
            if (userDO == null) {
                LOG.error("updata mail userDO is null, userDO={}, userId={}", userDO, userId);
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.NO_SUCH_USER;
            }
        } catch (Exception e) {
            LOG.error("update mail session error, updateMailVO={}, sessionId={}", updateMailVO, httpSession.getId(), e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }

        // 2.调用service
        ResultDO<Void> resultDO = userService.updateMail(userDO, updateMailVO.getMail());
        if (resultDO.isSuccess() == false) {
            LOG.error("update mail fail, updateMailVO={}, resultDO={}", updateMailVO, resultDO);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
        }
        SessionContentHolder.deleteSignInSessionBySessionId(httpSession.getId());
        // 重新种session
        SessionContentHolder.addSignInUserId(httpSession.getId(), userDO.getId());
        LOG.info("update mail success, updateMailVO={}, sessionId={}", updateMailVO, httpSession.getId());

        return TemplatePath.USER_UPDATE_MAIL_SUCCESS;
    }

    @Override
    @PostMapping("verify-identity-step-c")
    public String retrievePasswordStepC(@ModelAttribute UpdatePasswordVO updatePasswordVO, HttpSession httpSession) {
        // 参数校验
        if (StringUtils.isEmpty(httpSession.getId())) {
            LOG.error("retrieve password step c error, session is empty, updatePasswordVO={}, sessionId={}",
                updatePasswordVO, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.VERIFICATION_CODE_NOT_MATCH;
        }
        if (StringUtils.isBlank(updatePasswordVO.getNewPassword())
            || StringUtils.isBlank(updatePasswordVO.getConfirmNewPassword())) {
            LOG.error("retrieve password step c error, parameter illegal, updatePasswordVO={}, sessionId={}",
                updatePasswordVO, httpSession.getId());
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
        }

        String mail = SessionContentHolder.getMailBySessionId(httpSession.getId());
        if (StringUtils.isBlank(mail)) {
            LOG.error("retrievePasswordStepC error, mail is null, updatePasswordVO={}, httpSession={}",
                updatePasswordVO, httpSession);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
        try {
            // 邮箱找密
            if (!StringUtils.isBlank(mail)) {
                // 验证邮箱是否是刚才填的邮箱
                ResultDO<UserDO> resultDO = userService.getUserDOByMail(mail); // 返回结果判断
                if (resultDO.isSuccess() == false) {
                    LOG.error("get userDO by mail fail, resultDO={}, updatePasswordVO={}, sessionId={}", resultDO,
                        updatePasswordVO, httpSession.getId());
                    return "redirect:/" + StaticPath.COMMON_ERROR + "?" + resultDO.getMsg();
                }
            }
            // 验证新密二次确认
            if (StringUtils.equals(updatePasswordVO.getNewPassword(), updatePasswordVO.getConfirmNewPassword()) == false
                || StringUtils.isBlank(updatePasswordVO.getNewPassword())
                || StringUtils.isBlank(updatePasswordVO.getConfirmNewPassword())) {
                LOG.error("parameter illegal, updatePasswordVO={}, sessionId={}", updatePasswordVO,
                    httpSession.getId());
                // 重定向到文案提示页面
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
            }
            // 改密
            // 邮箱改密
            if (!StringUtils.isBlank(mail)) {
                ResultDO<Void> updatePasswordResultDO = userService.retrievePasswordByMail(mail,
                    updatePasswordVO.getNewPassword());
                if (updatePasswordResultDO.isSuccess() == false) {
                    LOG.error(
                        "user service retrieve pass word by mail fail, resultDO={}, updatePasswordVO={}, sessionId={}",
                        updatePasswordResultDO, updatePasswordVO, httpSession.getId());
                    return "redirect:/" + StaticPath.COMMON_ERROR + "?" + updatePasswordResultDO.getMsg();
                }
                SessionContentHolder.deleteMailSessionBySessionId(httpSession.getId());
                LOG.info("retrieve password by mail success, mail={}, updatePasswordVO={}, sessionId={}", mail,
                    updatePasswordResultDO, updatePasswordVO, httpSession.getId());
                return TemplatePath.USER_RETRIEVE_PASSWORD_SUCCESS;
            } else {
                LOG.error("retrieve password error, mail is null, updatePasswordVO={}, sessionId={}",
                    updatePasswordVO, httpSession.getId());
                return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.PARAMETER_INVALID;
            }
        } catch (Exception e) {
            LOG.error("retrieve password step c error, updatePasswordVO={}, sessionId={}", updatePasswordVO,
                httpSession.getId(), e);
            return "redirect:/" + StaticPath.COMMON_ERROR + "?" + ErrorText.SYSTEM_ERROR;
        }
    }

}
